package com.link.play.fit.ai.utils

import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentHashMap

@JvmInline
value class Event<T>(val event: String)

class FlowBus<T> private constructor(
    private val event: Event<T>
) : DefaultLifecycleObserver {

    companion object {
        private val busMap = ConcurrentHashMap<Event<*>, FlowBus<*>>()
        private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)

        fun <T> with(event: Event<T>): FlowBus<T> {
            @Suppress("UNCHECKED_CAST")
            return (busMap[event] ?: synchronized(this) {
                busMap[event] ?: FlowBus(event).also { busMap[event] = it }
            }) as FlowBus<T>
        }
    }

    private val _events = MutableSharedFlow<T>()

    fun subscribe(lifecycleOwner: LifecycleOwner, action: (t: T) -> Unit) {
        lifecycleOwner.lifecycle.addObserver(this)
        lifecycleOwner.lifecycleScope.launch {
            _events.collect {
                try {
                    action(it)
                } catch (e: Exception) {
                    LogX.e(msg = "Event[$event] error:$e")
                }
            }
        }
    }

    fun post(event: T) {
        scope.launch {
            _events.emit(event)
        }
    }

    override fun onDestroy(owner: LifecycleOwner) {
        val subscriptCount = _events.subscriptionCount.value
        if (subscriptCount <= 0) {
            busMap.remove(event)
        }
    }
}